Skip to main content

SSH Login Notification

SSH login notifications add a real-time signal to your server security posture: when a successful SSH session opens, the server sends an alert containing the account name, source IP, hostname, and timestamp. This helps with rapid detection of unexpected access, auditing of legitimate admin activity, and faster incident response.

What this covers
  • Triggering an alert on successful SSH logins (session open)
  • Two delivery methods: local mail (mailutils) and external SMTP (msmtp)
  • Safe PAM integration that does not block logins if the alert fails
Limitations
  • This alerts on successful logins, not failed attempts. Pair with fail2ban and SSH hardening for brute-force protection.
  • Email delivery from VPS providers may be restricted (blocked ports or poor deliverability). External SMTP is usually more reliable.

How It Works

On Linux, SSH sessions can be integrated with PAM (Pluggable Authentication Modules). PAM can run a script whenever a new SSH session is opened. The script gathers session details and sends an email.

Prerequisites

  • Root or sudo access

  • SSH server uses PAM (typical on Ubuntu/Debian)

  • A way to send mail:

    • Local mail (mailutils + a local MTA), or
    • External SMTP (msmtp, recommended for reliable delivery)

Verify SSH uses PAM (server)

Check /etc/ssh/sshd_config:

UsePAM yes

Validate config and restart SSH if you changed it:

sudo sshd -t
sudo systemctl restart ssh

Choose an Email Delivery Method

Local mail is simple but depends on your server’s ability to deliver email reliably. Some VPS providers block outbound SMTP or your messages may land in spam.

Method A: Local Mail Using mailutils

Step 1: Install mail tools

sudo apt update
sudo apt install mailutils -y

During installation, you may be prompted to configure an MTA (often Postfix). For basic usage you can pick:

  • Local only (quick setup)
  • Or configure appropriately if you need external delivery and your provider permits it

Step 2: Create the alert script

Create the script:

sudo nano /usr/local/bin/ssh_login_alert.sh

Paste this:

#!/bin/bash
# SSH login alert script (local mail)
# Runs from PAM. Keep it non-blocking and safe.

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

RECIPIENT_EMAIL="your-email@example.com"

# PAM environment variables commonly available:
# PAM_USER, PAM_RHOST, PAM_SERVICE, PAM_TTY, PAM_TYPE
USER_NAME="${PAM_USER:-unknown}"
REMOTE_HOST="${PAM_RHOST:-unknown}"
HOST="$(hostname -f 2>/dev/null || hostname)"
DATE="$(date -u +"%Y-%m-%d %H:%M:%S UTC")"

# Only notify on session open events (avoid other PAM phases)
if [ "${PAM_TYPE:-}" != "open_session" ]; then
exit 0
fi

# If PAM_RHOST is empty (local), skip or keep based on preference
if [ -z "${PAM_RHOST:-}" ]; then
exit 0
fi

SUBJECT="SSH login: ${USER_NAME} from ${REMOTE_HOST} on ${HOST}"

BODY="$(cat <<EOF
SSH login notification

Host: ${HOST}
User: ${USER_NAME}
Remote IP: ${REMOTE_HOST}
Service: ${PAM_SERVICE:-sshd}
TTY: ${PAM_TTY:-unknown}
Time: ${DATE}
EOF
)"

# Send mail (do not fail login if mail fails)
echo "$BODY" | /usr/bin/mail -s "$SUBJECT" "$RECIPIENT_EMAIL" 2>/dev/null || true

exit 0

Update:

  • RECIPIENT_EMAIL to your real email address

Make executable:

sudo chmod 700 /usr/local/bin/ssh_login_alert.sh
sudo chown root:root /usr/local/bin/ssh_login_alert.sh

Step 3: Enable PAM execution for SSH sessions

Edit PAM config:

sudo nano /etc/pam.d/sshd

Add at the bottom:

# SSH login notifications (do not block logins if script fails)
session optional pam_exec.so /usr/local/bin/ssh_login_alert.sh

Why optional matters:

  • If the script fails, the SSH login should still succeed

Step 4: Test

  1. Open a second terminal session (keep one session connected for safety).
  2. Log out and log back in via SSH.
  3. Check your inbox.

Server-side sanity checks:

sudo tail -n 200 /var/log/auth.log
sudo journalctl -u ssh -n 200 --no-pager

Step 1: Install msmtp

sudo apt update
sudo apt install msmtp msmtp-mta -y

Step 2: Configure msmtp (global config)

Create or edit:

sudo nano /etc/msmtprc

Template (TLS via STARTTLS on port 587):

defaults
auth on
tls on
tls_starttls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile /var/log/msmtp.log

account default
host smtp.your-provider.com
port 587
from server-alerts@your-domain.com
user your-smtp-username
password your-smtp-password

account default : default

Lock permissions (contains credentials):

sudo chown root:root /etc/msmtprc
sudo chmod 600 /etc/msmtprc

Create the log file (optional but useful):

sudo touch /var/log/msmtp.log
sudo chown root:root /var/log/msmtp.log
sudo chmod 600 /var/log/msmtp.log
Provider requirements

Many SMTP providers require:

  • The from address to be verified
  • TLS enabled
  • An app password (for Gmail/Google Workspace) instead of your normal password

Step 3: Create/update the alert script to use msmtp

Edit:

sudo nano /usr/local/bin/ssh_login_alert.sh

Paste this:

#!/bin/bash
# SSH login alert script (external SMTP via msmtp)
# Runs from PAM. Keep it non-blocking and safe.

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

RECIPIENT_EMAIL="your-personal-email@example.com"
FROM_EMAIL="server-alerts@your-domain.com"

USER_NAME="${PAM_USER:-unknown}"
REMOTE_HOST="${PAM_RHOST:-unknown}"
HOST="$(hostname -f 2>/dev/null || hostname)"
DATE="$(date -u +"%Y-%m-%d %H:%M:%S UTC")"

if [ "${PAM_TYPE:-}" != "open_session" ]; then
exit 0
fi

if [ -z "${PAM_RHOST:-}" ]; then
exit 0
fi

SUBJECT="SSH login: ${USER_NAME} from ${REMOTE_HOST} on ${HOST}"

BODY="$(cat <<EOF
SSH login notification

Host: ${HOST}
User: ${USER_NAME}
Remote IP: ${REMOTE_HOST}
Service: ${PAM_SERVICE:-sshd}
TTY: ${PAM_TTY:-unknown}
Time: ${DATE}
EOF
)"

# Construct RFC822 message and send via msmtp (-t reads headers)
(
echo "To: ${RECIPIENT_EMAIL}"
echo "From: ${FROM_EMAIL}"
echo "Subject: ${SUBJECT}"
echo
echo "${BODY}"
) | /usr/bin/msmtp --account=default -t 2>/dev/null || true

exit 0

Update:

  • RECIPIENT_EMAIL and FROM_EMAIL to match your SMTP configuration

Secure the script:

sudo chmod 700 /usr/local/bin/ssh_login_alert.sh
sudo chown root:root /usr/local/bin/ssh_login_alert.sh

Step 4: Enable PAM execution for SSH sessions

Edit:

sudo nano /etc/pam.d/sshd

Add at the bottom:

# SSH login notifications (do not block logins if script fails)
session optional pam_exec.so /usr/local/bin/ssh_login_alert.sh

Step 5: Test

  1. Log out and log back in via SSH.
  2. Confirm delivery in your inbox.

Check msmtp logs:

sudo tail -n 200 /var/log/msmtp.log

Optional Enhancements

Add Geo-IP Lookup (External Request)

This enriches notifications but depends on a third-party service and can fail if outbound HTTPS is blocked. Use only if acceptable for your environment.

Add this inside the script after REMOTE_HOST is known:

GEO_JSON="$(/usr/bin/curl -s --max-time 2 "https://ipinfo.io/${REMOTE_HOST}/json" || true)"

Then include GEO_JSON in the message body.

Notify Only for Specific Users

Example filter:

case "$USER_NAME" in
ubuntu|deploy|admin) ;;
*) exit 0 ;;
esac

Reduce Noise (Skip Non-interactive Sessions)

Some automation tools create SSH sessions without a full interactive TTY. You can skip if no TTY is present:

if [ -z "${PAM_TTY:-}" ] || [ "${PAM_TTY:-}" = "unknown" ]; then
exit 0
fi

Troubleshooting

SymptomLikely CauseChecks / Fix
---
No emails receivedDelivery blocked or misconfigured mailFor local mail: check postfix setup; for SMTP: verify /etc/msmtprc, provider credentials, TLS port
SSH works but no alertPAM not triggering scriptConfirm UsePAM yes; confirm line exists in /etc/pam.d/sshd
Script runs but email failsMissing binaries or PATH issuesUse full paths (/usr/bin/msmtp, /usr/bin/mail); confirm packages installed
Login delaysSlow network calls in scriptAvoid geo-IP or add timeouts (curl --max-time 2)
Provider rejects emailBad From address or authEnsure verified sender; use app password; confirm TLS port and settings

Useful logs:

sudo tail -n 200 /var/log/auth.log
sudo journalctl -u ssh -n 200 --no-pager

For external SMTP:

sudo tail -n 200 /var/log/msmtp.log

Rollback (Disable Notifications Safely)

  1. Remove or comment the line added to /etc/pam.d/sshd:
# session optional pam_exec.so /usr/local/bin/ssh_login_alert.sh
  1. Optionally remove script:
sudo rm -f /usr/local/bin/ssh_login_alert.sh
  1. New SSH sessions will no longer trigger alerts (no restart required for PAM changes).